package service

import (
	"a-common/constant"
	dom "a-common/domain"
	"a-common/utils"
	"a-system/dao"
	"a-system/domain/entity"
	"net/url"
	"strings"
	"sync"

	"github.com/gofiber/fiber/v2"
)

var (
	sysMenuServiceTemp *SysMenuService
	sysMenuDao         = dao.NewSysMenuDao()
	sysMenuServiceOnce sync.Once
)

type SysMenuService struct{}

func NewSysMenuService() *SysMenuService {
	sysMenuServiceOnce.Do(func() {
		sysMenuServiceTemp = &SysMenuService{}
	})
	return sysMenuServiceTemp
}

// List 分页
func (m *SysMenuService) List(args *entity.SysMenuDto, userId int64) (dom.PageVo, error) {
	return sysMenuDao.List(args, userId)
}

// Get 查
func (m *SysMenuService) Get(menuId string) (entity.SysMenuPageVo, error) {
	return sysMenuDao.Get(menuId)
}

func (m *SysMenuService) Add(args *entity.SysMenuDto) (int64, error) {
	return sysMenuDao.Add(args)
}

// Edit 改
func (m *SysMenuService) Edit(args *entity.SysMenuDto) (int64, error) {
	return sysMenuDao.Edit(args)
}

// Del 删
func (m *SysMenuService) Del(ids string) (int64, error) {
	return sysMenuDao.Del(ids)
}

// RoleMenuTreeselect 通过角色权限获取菜单树
func (m *SysMenuService) RoleMenuTreeselect(roleId string, uid int64) (fiber.Map, error) {
	// 获取选中项
	roleVo, err := sysRoleDao.Get(roleId)
	if err != nil {
		return nil, err
	}
	checkedKeys, err := sysMenuDao.GetmenuIdsByRoleId(roleVo.RoleId, roleVo.MenuCheckStrictly)
	if err != nil {
		return nil, err
	}

	// 构建菜单树
	vPage, err := sysMenuDao.List(&entity.SysMenuDto{}, uid)
	if err != nil {
		return nil, err
	}
	rows, _ := vPage.Rows.([]entity.SysMenuPageVo)

	treeUtils := utils.NewTreeUtils()

	var nodeList []*utils.TreeNode
	for _, item := range rows {
		nodeList = append(nodeList, &utils.TreeNode{
			ID:       int(item.MenuId),
			Label:    item.MenuName,
			ParentId: int(item.ParentId),
			Weight:   item.OrderNum,
		})
	}
	return fiber.Map{
		"checkedKeys": checkedKeys,
		"menus":       treeUtils.GetTreeRecursive(nodeList, 0),
	}, nil
}

// GetTree 获取菜单树
func (m *SysMenuService) GetTree(args *entity.SysMenuDto, uid int64) (nodeList []*utils.TreeNode, err error) {
	vPage, err := sysMenuDao.List(args, uid)
	if err != nil {
		return nodeList, err
	}
	rows, _ := vPage.Rows.([]entity.SysMenuPageVo)
	// 构建树
	treeUtils := utils.NewTreeUtils()
	for _, item := range rows {
		nodeList = append(nodeList, &utils.TreeNode{
			ID:       int(item.MenuId),
			Label:    item.MenuName,
			ParentId: int(item.ParentId),
			Weight:   item.OrderNum,
		})
	}
	nodeList = treeUtils.GetTreeRecursive(nodeList, 0)
	return nodeList, nil
}

// GetTreeSelect 获取菜单列表及根据权限id获取菜单id
func (m *SysMenuService) GetTreeSelect(ids string) (fiber.Map, error) {
	arr := strings.Split(ids, `,`)
	// 获取权限所拥有的菜单列表id
	checkedKeys, err := sysRoleDao.GetMenuIdsByRoleIds(arr)
	if err != nil {
		return nil, err
	}

	// 获取菜单列表
	// menuTree, err := sysMenuDao.GetTree()
	// if err != nil {
	// 	return err
	// }

	return fiber.Map{
		"checkedKeys": checkedKeys,
		"menuTree":    nil,
	}, nil
}

// getRouterPath 获取路由地址
func getRouterPath(v entity.SysMenuPageVo) string {
	routerPath := v.Path
	// 内链打开外网方式
	if v.ParentId != 0 && isInnerLink(v) {
		routerPath = innerLinkReplaceEach(routerPath)
	}
	// 非外链并且是一级目录（类型为目录）
	if v.ParentId == 0 && constant.TYPE_DIR == v.MenuType && constant.F == v.IsFrame {
		routerPath = "/" + v.Path
	} else
	// 非外链并且是一级目录（类型为菜单）
	if isMenuFrame(v) {
		routerPath = "/"
	}
	return routerPath
}

// 获取组件信息
func getComponent(v entity.SysMenuPageVo) string {
	component := constant.LAYOUT
	if v.Component != "" && !isMenuFrame(v) {
		component = v.Component
	} else if v.Component == "" && v.ParentId == 0 && isInnerLink(v) {
		component = constant.INNER_LINK
	} else if v.Component == "" && isParentView(v) {
		component = constant.PARENT_VIEW
	}
	return component
}

// isParentView 是否为parent_view组件
func isParentView(v entity.SysMenuPageVo) bool {
	return v.ParentId != 0 && constant.TYPE_DIR == v.MenuType
}

// isMenuFrame 是否为菜单内部跳转
func isMenuFrame(v entity.SysMenuPageVo) bool {
	return v.ParentId == 0 && constant.TYPE_MENU == v.MenuType && constant.F == v.IsFrame
}

// isInnerLink 是否为内链组件
func isInnerLink(v entity.SysMenuPageVo) bool {
	return constant.F == v.IsFrame && isURL(v.Path)
}

// 判断是否是链接地址
func isURL(str string) bool {
	parsedURL, err := url.Parse(str)
	if err != nil || parsedURL.Scheme == "" {
		return false
	}
	return true
}

// isInnerLink 是否为内链组件
func innerLinkReplaceEach(str string) string {
	str = strings.ReplaceAll(str, constant.HTTP, "")
	str = strings.ReplaceAll(str, constant.HTTPS, "")
	str = strings.ReplaceAll(str, constant.WWW, "")
	return str
}
